define([
    'json2',
    'jquery.format',
    'ace-language-tools',
    'js/factories/util',
    'js/factories/dialog'
], function(JSON2) {
    var itemEditorDirective = angular.module('app.directive.itemEditor', ['app.factory.util', 'app.factory.dialog']);

    itemEditorDirective.directive('itemEditor', ['$rootScope', '$timeout', 'xUtil', 'xDialog',
            function($rootScope, $timeout, xUtil, xDialog) {
        return {
            restrict: 'E',
            replace: true,
            scope: {
                attributes: '<',
                options: '<'
            },
            template: '<pre class="x-preview"></pre>',
            link: function(scope, element) {
                var attributes = scope.attributes;

                // editor
                var editor = ace.edit(element[0], angular.extend({
                    mode: 'ace/mode/text',
                    theme: 'ace/theme/chrome',
                    fontSize: 14,
                    wrap: true,
                    showPrintMargin: false,
                    maxLines: 100000,
                    autoScrollEditorIntoView: true,
                    enableBasicAutocompletion: true,
                    enableSnippets: true,
                    enableLiveAutocompletion: true
                }, scope.options));
                editor.renderer.setScrollMargin(10, 10, 0, 0);

                // Format code
                var formattedCode = '';
                editor.commands.addCommand({
                    name: 'format',
                    bindKey: { win: 'Ctrl-Shift-F', mac: 'Command-Option-F' },
                    exec: function(editor) {
                        var modeId = editor.getOption('mode');
                        if (editor.getValue() != formattedCode) {
                            if (modeId == 'ace/mode/hjson') {
                                formattedCode = JSON2.format(editor.getValue(), '    ');
                            } else if (modeId == 'ace/mode/xml') {
                                formattedCode = $.format(editor.getValue(), { method: 'xml' });
                            } else {
                                formattedCode = editor.getValue().trim();
                            }
                            editor.setValue(formattedCode, -1);
                            editor.resize();
                        }
                    }
                });
                // Goto line
                editor.commands.addCommand({
                    name: 'gotoline',
                    bindKey: { win: 'Ctrl-L', mac: 'Command-L' },
                    exec: function(editor) {
                        xDialog.open().showGotoLine({
                            maxLine: editor.session.getLength()
                        }).then(function(line) {
                            editor.gotoLine(line);
                        });
                    }
                });
                // Find and replace
                editor.commands.addCommand({
                    name: 'replace',
                    bindKey: { win: 'Ctrl-F', mac: 'Command-F' },
                    exec: function(editor) {
                        xUtil.searchbox.show(editor);
                    }
                });

                // Listen options
                scope.$on('editor.options', function(event, options) {
                    editor.setOptions(options);
                });
                // Listen action
                scope.$on('editor.action', function(event, action) {
                    if (action == 'format') {
                        editor.execCommand('format');
                    } else if (action == 'fold') {
                        editor.getSession().foldAll(0);
                    } else if (action == 'unfold') {
                        editor.getSession().unfold();
                    }
                });

                // Listen attributes
                var initItem = true;
                scope.$watch('attributes', function(newValue) {
                    if (attributes.id != newValue.id || initItem) {
                        attributes = newValue;
                        initItem = false;
                        editor.setValue(attributes.items[attributes.item], -1);
                        editor.resize();
                    }
                });

                // events
                editor.on('change', function(e) {
                    $timeout(function() {
                        attributes.items[attributes.item] = editor.getValue();
                    });
                });
                editor.on('focus', function() {
                    element.removeClass('x-preview');
                    //editor.resize();
                    $rootScope.$broadcast('editor.active', editor);
                });
                editor.on('blur', function() {
                    element.addClass('x-preview');
                    //editor.resize();
                });

                // resize
                scope.$on('@editor.resize', function() {
                    editor.resize();
                });

                // destroy
                scope.$on('$destroy', function() {
                    editor.destroy();
                    editor.container.remove();
                });
            }
        };
    }]);

    return itemEditorDirective;
});
